// Filename: lens.I
// Created by:  drose (29Nov01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//     Function: Lens::extrude
//       Access: Published
//  Description: Given a 2-d point in the range (-1,1) in both
//               dimensions, where (0,0) is the center of the
//               lens and (-1,-1) is the lower-left corner,
//               compute the corresponding vector in space that maps
//               to this point, if such a vector can be determined.
//               The vector is returned by indicating the points on
//               the near plane and far plane that both map to the
//               indicated 2-d point.
//
//               Returns true if the vector is defined, or false
//               otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
  CDReader cdata(_cycler);
  return do_extrude(cdata, LPoint3(point2d[0], point2d[1], 0.0f),
                    near_point, far_point);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::extrude
//       Access: Published
//  Description: Given a 2-d point in the range (-1,1) in both
//               dimensions, where (0,0) is the center of the
//               lens and (-1,-1) is the lower-left corner,
//               compute the corresponding vector in space that maps
//               to this point, if such a vector can be determined.
//               The vector is returned by indicating the points on
//               the near plane and far plane that both map to the
//               indicated 2-d point.
//
//               The z coordinate of the 2-d point is ignored.
//
//               Returns true if the vector is defined, or false
//               otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude(const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
  CDReader cdata(_cycler);
  return do_extrude(cdata, point2d, near_point, far_point);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::extrude_depth
//       Access: Published
//  Description: Uses the depth component of the 3-d result from
//               project() to compute the original point in 3-d space
//               corresponding to a particular point on the lens.
//               This exactly reverses project(), assuming the point
//               does fall legitimately within the lens.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude_depth(const LPoint3 &point2d, LPoint3 &point3d) const {
  CDReader cdata(_cycler);
  return do_extrude_depth(cdata, point2d, point3d);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::extrude_vec
//       Access: Published
//  Description: Given a 2-d point in the range (-1,1) in both
//               dimensions, where (0,0) is the center of the
//               lens and (-1,-1) is the lower-left corner,
//               compute the vector that corresponds to the view
//               direction.  This will be parallel to the normal on
//               the surface (the far plane) corresponding to the lens
//               shape at this point.
//
//               See the comment block on Lens::extrude_vec_impl() for
//               a more in-depth comment on the meaning of this
//               vector.
//
//               Returns true if the vector is defined, or false
//               otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude_vec(const LPoint2 &point2d, LVector3 &vec) const {
  CDReader cdata(_cycler);
  return do_extrude_vec(cdata, LPoint3(point2d[0], point2d[1], 0.0f), vec);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::extrude_vec
//       Access: Published
//  Description: Given a 2-d point in the range (-1,1) in both
//               dimensions, where (0,0) is the center of the
//               lens and (-1,-1) is the lower-left corner,
//               compute the vector that corresponds to the view
//               direction.  This will be parallel to the normal on
//               the surface (the far plane) corresponding to the lens
//               shape at this point.
//
//               See the comment block on Lens::extrude_vec_impl() for
//               a more in-depth comment on the meaning of this
//               vector.
//
//               The z coordinate of the 2-d point is ignored.
//
//               Returns true if the vector is defined, or false
//               otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
extrude_vec(const LPoint3 &point2d, LVector3 &vec) const {
  CDReader cdata(_cycler);
  return do_extrude_vec(cdata, point2d, vec);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::project
//       Access: Published
//  Description: Given a 3-d point in space, determine the 2-d point
//               this maps to, in the range (-1,1) in both dimensions,
//               where (0,0) is the center of the lens and
//               (-1,-1) is the lower-left corner.
//
//               Returns true if the 3-d point is in front of the lens
//               and within the viewing frustum (in which case point2d
//               is filled in), or false otherwise (in which case
//               point2d will be filled in with something, which may
//               or may not be meaningful).
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
project(const LPoint3 &point3d, LPoint2 &point2d) const {
  CDReader cdata(_cycler);
  LPoint3 result;
  bool okflag = do_project(cdata, point3d, result);
  point2d.set(result[0], result[1]);
  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::project
//       Access: Published
//  Description: Given a 3-d point in space, determine the 2-d point
//               this maps to, in the range (-1,1) in both dimensions,
//               where (0,0) is the center of the lens and
//               (-1,-1) is the lower-left corner.
//
//               The z coordinate will also be set to a value in the
//               range (-1, 1), where 1 represents a point on the near
//               plane, and -1 represents a point on the far plane.
//
//               Returns true if the 3-d point is in front of the lens
//               and within the viewing frustum (in which case point2d
//               is filled in), or false otherwise (in which case
//               point2d will be filled in with something, which may
//               or may not be meaningful).
////////////////////////////////////////////////////////////////////
INLINE bool Lens::
project(const LPoint3 &point3d, LPoint3 &point2d) const {
  CDReader cdata(_cycler);
  return do_project(cdata, point3d, point2d);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_change_event
//       Access: Published
//  Description: Sets the name of the event that will be generated
//               whenever any properties of the Lens have
//               changed.  If this is not set for a particular lens,
//               no event will be generated.
//
//               The event is thrown with one parameter, the lens
//               itself.  This can be used to automatically track
//               changes to camera fov, etc. in the application.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_change_event(const string &event) {
  CDWriter cdata(_cycler, true);
  cdata->_change_event = event;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_change_event
//       Access: Published
//  Description: Returns the name of the event that will be generated
//               whenever any properties of this particular Lens have
//               changed.
////////////////////////////////////////////////////////////////////
INLINE const string &Lens::
get_change_event() const {
  CDReader cdata(_cycler);
  return cdata->_change_event;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_coordinate_system
//       Access: Published
//  Description: Returns the coordinate system that all 3-d
//               computations are performed within for this
//               Lens.  Normally, this is CS_default.
////////////////////////////////////////////////////////////////////
INLINE CoordinateSystem Lens::
get_coordinate_system() const {
  CDReader cdata(_cycler);
  return cdata->_cs;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_film_size
//       Access: Published
//  Description: Sets the horizontal size of the film without changing
//               its shape.  The aspect ratio remains unchanged; this
//               computes the vertical size of the film to
//               automatically maintain the aspect ratio.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_film_size(PN_stdfloat width) {
  CDWriter cdata(_cycler, true);
  do_set_film_size(cdata, width);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_film_size
//       Access: Published
//  Description: Sets the size and shape of the "film" within the
//               lens.  This both establishes the units used by
//               calls like set_focal_length(), and establishes the
//               aspect ratio of the frame.
//
//               In a physical camera, the field of view of a lens is
//               determined by the lens' focal length and by the size
//               of the film area exposed by the lens.  For instance,
//               a 35mm camera exposes a rectangle on the film about
//               24mm x 36mm, which means a 50mm lens gives about a
//               40-degree horizontal field of view.
//
//               In the virtual camera, you may set the film size to
//               any units here, and specify a focal length in the
//               same units to simulate the same effect.  Or, you may
//               ignore this parameter, and specify the field of view
//               and aspect ratio of the lens directly.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_film_size(PN_stdfloat width, PN_stdfloat height) {
  set_film_size(LVecBase2(width, height));
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_film_size
//       Access: Published
//  Description: Sets the size and shape of the "film" within the
//               lens.  This both establishes the units used by
//               calls like set_focal_length(), and establishes the
//               aspect ratio of the frame.
//
//               In a physical camera, the field of view of a lens is
//               determined by the lens' focal length and by the size
//               of the film area exposed by the lens.  For instance,
//               a 35mm camera exposes a rectangle on the film about
//               24mm x 36mm, which means a 50mm lens gives about a
//               40-degree horizontal field of view.
//
//               In the virtual camera, you may set the film size to
//               any units here, and specify a focal length in the
//               same units to simulate the same effect.  Or, you may
//               ignore this parameter, and specify the field of view
//               and aspect ratio of the lens directly.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_film_size(const LVecBase2 &film_size) {
  CDWriter cdata(_cycler, true);
  do_set_film_size(cdata, film_size);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_film_size
//       Access: Published
//  Description: Returns the horizontal and vertical film size of
//               the virtual film.  See set_film_size().
////////////////////////////////////////////////////////////////////
INLINE const LVecBase2 &Lens::
get_film_size() const {
  CDReader cdata(_cycler);
  return do_get_film_size(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_film_offset
//       Access: Published
//  Description: Sets the horizontal and vertical offset amounts of
//               this Lens.  These are both in the same units
//               specified in set_film_size().
//
//               This can be used to establish an off-axis lens.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_film_offset(PN_stdfloat x, PN_stdfloat y) {
  set_film_offset(LVecBase2(x, y));
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_film_offset
//       Access: Published
//  Description: Sets the horizontal and vertical offset amounts of
//               this Lens.  These are both in the same units
//               specified in set_film_size().
//
//               This can be used to establish an off-axis lens.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_film_offset(const LVecBase2 &film_offset) {
  CDWriter cdata(_cycler, true);
  do_set_film_offset(cdata, film_offset);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_film_offset
//       Access: Published
//  Description: Returns the horizontal and vertical offset amounts of
//               this Lens.  See set_film_offset().
////////////////////////////////////////////////////////////////////
INLINE const LVector2 &Lens::
get_film_offset() const {
  CDReader cdata(_cycler);
  return do_get_film_offset(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_focal_length
//       Access: Published
//  Description: Sets the focal length of the lens.  This may adjust
//               the field-of-view correspondingly, and is an
//               alternate way to specify field of view.
//
//               For certain kinds of lenses (e.g. OrthographicLens),
//               the focal length has no meaning.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_focal_length(PN_stdfloat focal_length) {
  CDWriter cdata(_cycler, true);
  do_set_focal_length(cdata, focal_length);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_focal_length
//       Access: Published
//  Description: Returns the focal length of the lens.  This may have
//               been set explicitly by a previous call to
//               set_focal_length(), or it may be computed based on
//               the lens' fov and film_size.  For certain kinds of
//               lenses, the focal length has no meaning.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_focal_length() const {
  CDReader cdata(_cycler);
  return do_get_focal_length(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_fov
//       Access: Published
//  Description: Sets the horizontal field of view of the lens without
//               changing the aspect ratio.  The vertical field of
//               view is adjusted to maintain the same aspect ratio.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_fov(PN_stdfloat hfov) {
  CDWriter cdata(_cycler, true);
  do_set_fov(cdata, hfov);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_fov
//       Access: Published
//  Description: Sets the field of view of the lens in both
//               dimensions.  This establishes both the field of view
//               and the aspect ratio of the lens.  This is one way to
//               specify the field of view of a lens;
//               set_focal_length() is another way.
//
//               For certain kinds of lenses (like OrthoLens),
//               the field of view has no meaning.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_fov(PN_stdfloat hfov, PN_stdfloat vfov) {
  set_fov(LVecBase2(hfov, vfov));
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_fov
//       Access: Published
//  Description: Sets the field of view of the lens in both
//               dimensions.  This establishes both the field of view
//               and the aspect ratio of the lens.  This is one way to
//               specify the field of view of a lens;
//               set_focal_length() is another way.
//
//               For certain kinds of lenses (like OrthographicLens),
//               the field of view has no meaning.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_fov(const LVecBase2 &fov) {
  CDWriter cdata(_cycler, true);
  do_set_fov(cdata, fov);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_fov
//       Access: Published
//  Description: Returns the horizontal and vertical film size of
//               the virtual film.  See set_fov().
////////////////////////////////////////////////////////////////////
INLINE const LVecBase2 &Lens::
get_fov() const {
  CDReader cdata(_cycler);
  return do_get_fov(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_hfov
//       Access: Published
//  Description: Returns the horizontal component of fov only.  See
//               get_fov().
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_hfov() const {
  return get_fov()[0];
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_vfov
//       Access: Published
//  Description: Returns the vertical component of fov only.  See
//               get_fov().
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_vfov() const {
  return get_fov()[1];
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_aspect_ratio
//       Access: Published
//  Description: Sets the aspect ratio of the lens.  This is the ratio
//               of the height to the width of the generated image.
//               Setting this overrides the two-parameter fov or film
//               size setting.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_aspect_ratio(PN_stdfloat aspect_ratio) {
  CDWriter cdata(_cycler, true);
  do_set_aspect_ratio(cdata, aspect_ratio);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_aspect_ratio
//       Access: Published
//  Description: Returns the aspect ratio of the Lens.  This is
//               determined based on the indicated film size; see
//               set_film_size().
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_aspect_ratio() const {
  CDReader cdata(_cycler);
  return do_get_aspect_ratio(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_near
//       Access: Published
//  Description: Defines the position of the near plane (or cylinder,
//               sphere, whatever).  Points closer to the lens than
//               this may not be rendered.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_near(PN_stdfloat near_distance) {
  CDWriter cdata(_cycler, true);
  do_set_near(cdata, near_distance);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_near
//       Access: Published
//  Description: Returns the position of the near plane (or cylinder,
//               sphere, whatever).
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_near() const {
  CDReader cdata(_cycler);
  return do_get_near(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_far
//       Access: Published
//  Description: Defines the position of the far plane (or cylinder,
//               sphere, whatever).  Points farther from the lens than
//               this may not be rendered.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_far(PN_stdfloat far_distance) {
  CDWriter cdata(_cycler, true);
  do_set_far(cdata, far_distance);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_far
//       Access: Published
//  Description: Returns the position of the far plane (or cylinder,
//               sphere, whatever).
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_far() const {
  CDReader cdata(_cycler);
  return do_get_far(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_near_far
//       Access: Published
//  Description: Simultaneously changes the near and far planes.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_near_far(PN_stdfloat near_distance, PN_stdfloat far_distance) {
  CDWriter cdata(_cycler, true);
  do_set_near_far(cdata, near_distance, far_distance);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_view_hpr
//       Access: Published
//  Description: Sets the direction in which the lens is facing.
//               Normally, this is down the forward axis (usually the
//               Y axis), but it may be rotated.  This is only one way
//               of specifying the rotation; you may also specify an
//               explicit vector in which to look, or you may give a
//               complete transformation matrix.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_view_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
  set_view_hpr(LVecBase3(h, p, r));
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_view_vector
//       Access: Published
//  Description: Specifies the direction in which the lens is facing
//               by giving an axis to look along, and a perpendicular
//               (or at least non-parallel) up axis.
//
//               See also set_view_hpr().
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_view_vector(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat i, PN_stdfloat j, PN_stdfloat k) {
  set_view_vector(LVector3(x, y, z), LVector3(i, j, k));
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_interocular_distance
//       Access: Published
//  Description: Sets the distance between the left and right eyes of
//               a stereo camera.  This distance is used to apply a
//               stereo effect when the lens is rendered on a stereo
//               display region.  It only has an effect on a
//               PerspectiveLens.
//
//               The left eye and the right eye are each offset along
//               the X axis by half of this distance, so that this
//               parameter specifies the total distance between them.
//
//               Also see set_convergence_distance(), which relates.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_interocular_distance(PN_stdfloat interocular_distance) {
  CDWriter cdata(_cycler, true);
  do_set_interocular_distance(cdata, interocular_distance);
  do_throw_change_event(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_interocular_distance
//       Access: Published
//  Description: See set_interocular_distance().
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_interocular_distance() const {
  CDReader cdata(_cycler);
  return cdata->_interocular_distance;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_convergence_distance
//       Access: Published
//  Description: Sets the distance between between the camera plane
//               and the point in the distance that the left and right
//               eyes are both looking at.  This distance is used to
//               apply a stereo effect when the lens is rendered on a
//               stereo display region.  It only has an effect on a
//               PerspectiveLens.
//
//               This parameter must be greater than 0, but may be as
//               large as you like.  It controls the distance at
//               which the two stereo images will appear to converge,
//               which is a normal property of stereo vision.  Normally
//               this should be set to the distance from the camera to
//               the area of interest in your scene.  Anything beyond
//               this distance will appear to go into the screen, and
//               anything closer will appear to come out of the screen.
//               If you want to simulate parallel stereo, set this
//               to infinity.
//
//               Note that this creates an off-axis frustum, which
//               means that the lenses are still pointing in the
//               same direction, which is usually more desirable
//               than the more naive toe-in approach, where the
//               two lenses are simply tilted toward each other.
//
//               Prior to Panda3D 1.9.0, the convergence was being
//               calculated incorrectly.  It has since been corrected.
//               To restore the legacy behavior you can set the
//               stereo-lens-old-convergence variable to true.
//
//               Also see set_interocular_distance(), which relates.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_convergence_distance(PN_stdfloat convergence_distance) {
  CDWriter cdata(_cycler, true);
  do_set_convergence_distance(cdata, convergence_distance);
  do_throw_change_event(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_convergence_distance
//       Access: Published
//  Description: See set_convergence_distance().
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
get_convergence_distance() const {
  CDReader cdata(_cycler);
  return cdata->_convergence_distance;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::set_view_mat
//       Access: Published
//  Description: Sets an arbitrary transformation on the lens.  This
//               replaces the individual transformation components
//               like set_view_hpr().
//
//               Setting a transformation here will have a slightly
//               different effect than putting one on the LensNode
//               that contains this lens.  In particular, lighting and
//               other effects computations will still be performed on
//               the lens in its untransformed (facing forward)
//               position, but the actual projection matrix will be
//               transformed by this matrix.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
set_view_mat(const LMatrix4 &view_mat) {
  CDWriter cdata(_cycler, true);
  do_set_view_mat(cdata, view_mat);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_view_mat
//       Access: Published
//  Description: Returns the direction in which the lens is facing.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_view_mat() const {
  CDReader cdata(_cycler);
  return do_get_view_mat(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_keystone
//       Access: Published
//  Description: Returns the keystone correction specified for the
//               lens.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase2 &Lens::
get_keystone() const {
  CDReader cdata(_cycler);
  return cdata->_keystone;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_custom_film_mat
//       Access: Published
//  Description: Returns the custom_film_mat specified for the
//               lens.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_custom_film_mat() const {
  CDReader cdata(_cycler);
  return cdata->_custom_film_mat;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_projection_mat
//       Access: Published
//  Description: Returns the complete transformation matrix from a 3-d
//               point in space to a point on the film, if such a
//               matrix exists, or the identity matrix if the lens is
//               nonlinear.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_projection_mat(StereoChannel channel) const {
  CDReader cdata(_cycler);
  return do_get_projection_mat(cdata, channel);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_projection_mat_inv
//       Access: Published
//  Description: Returns the matrix that transforms from a 2-d point
//               on the film to a 3-d vector in space, if such a
//               matrix exists.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_projection_mat_inv(StereoChannel stereo_channel) const {
  CDReader cdata(_cycler);
  return do_get_projection_mat_inv(cdata, stereo_channel);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_film_mat
//       Access: Published
//  Description: Returns the matrix that transforms from a point
//               behind the lens to a point on the film.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_film_mat() const {
  CDReader cdata(_cycler);
  return do_get_film_mat(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_film_mat_inv
//       Access: Published
//  Description: Returns the matrix that transforms from a point on
//               the film to a point behind the lens.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_film_mat_inv() const {
  CDReader cdata(_cycler);
  return do_get_film_mat_inv(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_lens_mat
//       Access: Published
//  Description: Returns the matrix that transforms from a point
//               in front of the lens to a point in space.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_lens_mat() const {
  CDReader cdata(_cycler);
  return do_get_lens_mat(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_lens_mat_inv
//       Access: Published
//  Description: Returns the matrix that transforms from a point in
//               space to a point in front of the lens.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4 &Lens::
get_lens_mat_inv() const {
  CDReader cdata(_cycler);
  return do_get_lens_mat_inv(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::get_last_change
//       Access: Published
//  Description: Returns the UpdateSeq that is incremented whenever
//               the lens properties are changed.  As long as this
//               number remains the same, you may assume the lens
//               properties are unchanged.
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq Lens::
get_last_change() const {
  CDReader cdata(_cycler);
  return cdata->_last_change;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_adjust_user_flags
//       Access: Protected
//  Description: Clears from _user_flags the bits in the first
//               parameter, and sets the bits in the second parameter.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_adjust_user_flags(CData *cdata, int clear_flags, int set_flags) {
  cdata->_user_flags = (cdata->_user_flags & ~clear_flags) | (short)set_flags;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_adjust_comp_flags
//       Access: Protected
//  Description: Clears from _comp_flags the bits in the first
//               parameter, and sets the bits in the second parameter.
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_adjust_comp_flags(CData *cdata, int clear_flags, int set_flags) {
  cdata->_comp_flags = (cdata->_comp_flags & ~clear_flags) | (short)set_flags;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_set_film_offset
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_set_film_offset(CData *cdata, const LVecBase2 &film_offset) {
  cdata->_film_offset = film_offset;
  do_adjust_comp_flags(cdata, CF_mat, 0);
  do_throw_change_event(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_get_film_offset
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE const LVector2 &Lens::
do_get_film_offset(const CData *cdata) const {
  return cdata->_film_offset;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_set_near
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_set_near(CData *cdata, PN_stdfloat near_distance) {
  cdata->_near_distance = near_distance;
  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
  do_throw_change_event(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_get_near
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
do_get_near(const CData *cdata) const {
  return cdata->_near_distance;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_set_far
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_set_far(CData *cdata, PN_stdfloat far_distance) {
  cdata->_far_distance = far_distance;
  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
  do_throw_change_event(cdata);
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_get_far
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat Lens::
do_get_far(const CData *cdata) const {
  return cdata->_far_distance;
}

////////////////////////////////////////////////////////////////////
//     Function: Lens::do_set_near_far
//       Access: Protected
//  Description:
////////////////////////////////////////////////////////////////////
INLINE void Lens::
do_set_near_far(CData *cdata, PN_stdfloat near_distance, PN_stdfloat far_distance) {
  cdata->_near_distance = near_distance;
  cdata->_far_distance = far_distance;
  do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv, 0);
  do_throw_change_event(cdata);
}

INLINE ostream &
operator << (ostream &out, const Lens &lens) {
  lens.output(out);
  return out;
}

